package br.com.leopard.erp.gym.persistence;

import java.util.Iterator;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;

import br.com.leopard.erp.gym.conf.ConstantesSistema;
import br.com.leopard.erp.gym.conf.StatusRegistro;
import br.com.leopard.erp.gym.exception.NenhumResultadoEncontradoException;
import br.com.leopard.erp.gym.mapeamento.base_sistema.AbstractPersistenceClass;
import br.com.leopard.util.text.ConversaoString;
import br.com.leopard.util.text.ConversaoStringUpperCase;

public class AbstractDAO<T extends AbstractPersistenceClass, PK> {

	@PersistenceContext(unitName = ConstantesSistema.DATA_SOURCE)
	protected EntityManager entityManager;

	private Class<T> type;

	public AbstractDAO(Class<T> type) {
		this.type = type;
	}

	public Long getCountAtivos() {
		return countStatus(StatusRegistro.ATIVO);
	}

	public Long getCountInativos() {
		return countStatus(StatusRegistro.INATIVO);
	}

	public Long getCount() {
		return countStatus(StatusRegistro.TODOS);
	}

	public void ativar(T t) {
		t.setAtivo(StatusRegistro.ATIVO.getStatus());

		this.update(t);
	}

	public void inativar(T t) {
		t.setAtivo(StatusRegistro.INATIVO.getStatus());

		this.update(t);
	}

	public List<T> ListAll() {
		StringBuffer buffer = new StringBuffer();
		buffer.append("SELECT p FROM  " + type.getName() + " p");

		TypedQuery<T> query = entityManager.createQuery(buffer.toString(), type);

		return query.getResultList();
	}

	private List<T> ListAllByStatus(StatusRegistro status) {
		StringBuffer buffer = new StringBuffer();
		buffer.append("SELECT p FROM  " + type.getName() + " p WHERE p.ativo=:ativo");

		TypedQuery<T> query = entityManager.createQuery(buffer.toString(), type);
		query.setParameter("ativo", status.getStatus());

		return query.getResultList();
	}

	public List<T> ListAllAtivos() {
		return ListAllByStatus(StatusRegistro.ATIVO);
	}

	public List<T> ListAllInativos() {
		return ListAllByStatus(StatusRegistro.INATIVO);
	}

	public List<T> ListAllLimited(Integer limitRows) {
		StringBuffer buffer = new StringBuffer();
		buffer.append(" SELECT t FROM  " + type.getSimpleName() + " t ORDER BY 1 ASC");

		TypedQuery<T> query = entityManager.createQuery(buffer.toString(), type);
		query.setMaxResults(limitRows);

		return query.getResultList();
	}

	public List<T> ListAllPagining(Integer page, Integer rowsPerPage) {
		StringBuffer buffer = new StringBuffer();
		buffer.append("SELECT t FROM  " + type.getName() + " t ORDER BY 1 ASC");

		TypedQuery<T> query = entityManager.createQuery(buffer.toString(), type);
		query.setMaxResults(rowsPerPage);
		query.setFirstResult(page * rowsPerPage);

		return query.getResultList();
	}

	public T get(PK pk) {
		return entityManager.find(type, pk);
	}

	public T save(T t) {
		ConversaoString conversao = new ConversaoStringUpperCase();
		conversao.converter(t);

		entityManager.persist(t);
		entityManager.flush();

		return t;
	}

	public void update(T t) {
		ConversaoString conversao = new ConversaoStringUpperCase();
		conversao.converter(t);

		entityManager.merge(t);
		entityManager.flush();
	}

	public void remove(T t) {
		entityManager.remove(entityManager.contains(t) ? t : entityManager.merge(t));
		entityManager.flush();
	}

	public List<T> listNamedQuery(String namedQuery, List<ParametroQuery> parametros) {
		return montarQuery(namedQuery, parametros).getResultList();
	}

	protected void executeUpdate(String namedQuery, List<ParametroQuery> parametros) {
		montarQuery(namedQuery, parametros).executeUpdate();
	}

	public T getSingleObject(String namedQuery, List<ParametroQuery> parametros) throws NenhumResultadoEncontradoException {
		try {
			return montarQuery(namedQuery, parametros).getSingleResult();
		} catch (NoResultException nex) {
			throw new NenhumResultadoEncontradoException();
		}
	}

	private TypedQuery<T> montarQuery(String namedQuery, List<ParametroQuery> parametros) {
		TypedQuery<T> query = this.entityManager.createNamedQuery(namedQuery, type);

		for (Iterator<ParametroQuery> iterator = parametros.iterator(); iterator.hasNext();) {
			ParametroQuery parametroQuery = (ParametroQuery) iterator.next();

			query.setParameter(parametroQuery.getParametro(), parametroQuery.getValor());
		}

		return query;
	}

	private Long countStatus(StatusRegistro status) {
		StringBuffer buffer = new StringBuffer();
		buffer.append("SELECT COUNT(1) FROM  " + type.getSimpleName());

		if (status != StatusRegistro.TODOS) {
			buffer.append(" WHERE ativo=:ativo");
		}

		TypedQuery<Long> query = entityManager.createQuery(buffer.toString(), Long.class);

		if (status != StatusRegistro.TODOS) {
			query.setParameter("ativo", status.getStatus());
		}

		return query.getSingleResult();
	}
}